﻿
#if !DEBUG
#   define STORE_USERAGENT
#endif

using System;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Web.Script.Serialization;
using System.Windows.Threading;
using Red.Core.GoogleAnalytics;
using Red.Core.Network;
using Red.Launcher.Utilities;
using System.Text.RegularExpressions;

namespace Red.Launcher
{
    public partial class App
    {
        #region Private Types

        private class SystemInfo
        {
            public int Width { get; set; }
            public int Height { get; set; }
            public int Depth { get; set; }
            public string Locale { get; set; }
            public string UserAgent { get; set; }
        }

        #endregion Private Types

        #region Private Data

        SystemInfo _previous;

        #endregion Private Data

        #region C-Tor

        partial void InitializeAnalytics()
        {
            GoogleAnalyticsService.Instance.DebugResponse += AnalyticsService_DebugResponse;

            DispatcherUnhandledException += App_DispatcherUnhandledException;
            AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
        }

        #endregion C-Tor

        #region Private Methods

        private SystemInfo ExtractSystemInfoFromQueryString( CustomWebRequest request )
        {
            Regex regex = new Regex( @"sr=(\d+)x(\d+).*sd=(\d+)-bits.*ul=(\w{2,3}-\w{2,3}).*ua=(\(.*\))", RegexOptions.Compiled );
            MatchCollection resolutionMatches = regex.Matches( request.QueryString );

            if ( resolutionMatches.Count != 1 || resolutionMatches[ 0 ].Groups.Count != 6 )
                return null;

            SystemInfo info = new SystemInfo();

            info.Width = int.Parse( resolutionMatches[ 0 ].Groups[ 1 ].Value );
            info.Height = int.Parse( resolutionMatches[ 0 ].Groups[ 2 ].Value );
            info.Depth = int.Parse( resolutionMatches[ 0 ].Groups[ 3 ].Value );
            info.Locale = resolutionMatches[ 0 ].Groups[ 4 ].Value;
            info.UserAgent = resolutionMatches[ 0 ].Groups[ 5 ].Value;

            return info;
        }

        private async Task StoreResponse( CustomWebRequest request, string response, SystemInfo info )
        {
            SqlParameter[] sqlParams = new SqlParameter[ 8 ];

            sqlParams[ 0 ] = new SqlParameter( "@address", request.Address );
            sqlParams[ 1 ] = new SqlParameter( "@request", request.QueryString );
            sqlParams[ 2 ] = new SqlParameter( "@response", response );
            sqlParams[ 3 ] = new SqlParameter( "@userAgent", (object)info?.UserAgent ?? DBNull.Value );
            sqlParams[ 4 ] = new SqlParameter( "@locale", (object)info?.Locale ?? DBNull.Value );
            sqlParams[ 5 ] = new SqlParameter( "@screenWidth", (object)info?.Width ?? DBNull.Value );
            sqlParams[ 6 ] = new SqlParameter( "@screenHeight", (object)info?.Height ?? DBNull.Value );
            sqlParams[ 7 ] = new SqlParameter( "@screenDepth", (object)info?.Depth ?? DBNull.Value );

            string sql = @" INSERT INTO [Workspaces].[dbo].[GoogleAnalyticsDebug]
                                ( [address], [request], [response], [userAgent], [locale], [screenWidth], [screenHeight], [screenDepth] )
                                VALUES
                                ( @address, @request, @response, @userAgent, @locale, @screenWidth, @screenHeight, @screenDepth )";
            string conn = @"Data Source=CDPRS-MSSQL\sqlexpress;Integrated Security=True";

            await DatabaseHelper.ExecuteAsync( sql, conn, sqlParams );
        }

        [Conditional( "STORE_USERAGENT" )]
        private async void StoreSystemInfo( SystemInfo info )
        {
            if
            (
                _previous == null ||
                _previous.UserAgent != info.UserAgent ||
                _previous.Locale != info.Locale ||
                _previous.Width != info.Width ||
                _previous.Height != info.Height ||
                _previous.Depth != info.Depth
            )
            {
                SqlParameter[] sqlParams = new SqlParameter[ 6 ];
                sqlParams[ 0 ] = new SqlParameter( "@agent", (object)info?.UserAgent ?? DBNull.Value );
                sqlParams[ 1 ] = new SqlParameter( "@user", User.UserPrincipalName );
                sqlParams[ 2 ] = new SqlParameter( "@locale", (object)info?.Locale ?? DBNull.Value );
                sqlParams[ 3 ] = new SqlParameter( "@screenWidth", (object)info?.Width ?? DBNull.Value );
                sqlParams[ 4 ] = new SqlParameter( "@screenHeight", (object)info?.Height ?? DBNull.Value );
                sqlParams[ 5 ] = new SqlParameter( "@screenDepth", (object)info?.Depth ?? DBNull.Value );

                string conn = @"Data Source=CDPRS-MSSQL\sqlexpress;Integrated Security=True";
                string sql = @"INSERT INTO [Workspaces].[dbo].[GoogleAnalyticsDebugUA] ( [useragent], [username], [locale], [screenWidth], [screenHeight], [screenDepth] ) VALUES ( @agent, @user, @locale, @screenWidth, @screenHeight, @screenDepth )";

                _previous = info;

                await DatabaseHelper.ExecuteAsync( sql, conn, sqlParams );
            }
        }

        #endregion Private Methods

        #region Event Handlers

        private async void AnalyticsService_DebugResponse( CustomWebRequest request, string response )
        {
            SystemInfo info = ExtractSystemInfoFromQueryString( request );

            StoreSystemInfo( info );

            if ( info == null )
            {
                await StoreResponse( request, response, info );
            }
            else
            {
                JavaScriptSerializer serializer = new JavaScriptSerializer();
                GoogleResponse responseObj = serializer.Deserialize<GoogleResponse>( response );

                foreach ( var hit in responseObj.hitParsingResult )
                {
                    if ( !hit.valid )
                    {
                        await StoreResponse( request, response, info );
                        break;
                    }
                }
            }
        }

        private void App_DispatcherUnhandledException( object sender, DispatcherUnhandledExceptionEventArgs e )
        {
            GoogleAnalyticsService.Instance.SendException( e.Exception );
        }

        private void CurrentDomain_UnhandledException( object sender, UnhandledExceptionEventArgs e )
        {
            GoogleAnalyticsService.Instance.SendException( (Exception)e.ExceptionObject, e.IsTerminating );
        }

        #endregion Event Handlers
    }
}
